package com.tengju.bff.application.wx;

import com.tengju.bff.application.shared.ApplicationException;
import com.tengju.bff.application.shared.ApplicationExceptionCode;
import com.tengju.data.domain.model.user.UserIdCode;
import com.tengju.data.domain.model.wx.WxActivateStatus;
import com.tengju.data.domain.model.wx.WxUserInfo;
import com.tengju.data.domain.model.wx.WxUserInfoRepository;
import com.tengju.support.domain.model.wx.*;
import com.tengju.support.domain.service.WeiXinCompanyService;
import com.tengju.user.domain.model.csm.dealer.CrmDealerInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.tengju.bff.application.shared.ApplicationExceptionCode.WORK_WEIXIN_DEALER_INFO_NOT_EXIST;

/**
 * @author: 李大仙
 * @date: 2021/11/10 2:32 下午
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class WxUserManageService {

    private final WeiXinCompanyService weiXinCompanyService;
    private final WxUserInfoRepository wxUserInfoRepository;

    @Value("${weixin.work.user.root.department.id}")
    private String weixinRootDepartmentIdStr;
    @Value("${weixin.work.user.invalid.department.id}")
    private String weixinInvalidDepartmentIdStr;
    @Value("${weixin.work.user.to.invite}")
    private boolean weixinUserToInvite;
    @Value("#{${weixin.work.tag.map}}")
    private Map<String, Long> weixinTagMap;

    private static final Long wxMaxId = 4294967295L;

    public void deleteDepartment(WxUserInfo wxUserInfo) {
        // 删除当前部门（将删除的部门移到无效部门）
        DepartmentId departmentId = new DepartmentId(wxUserInfo.getDepartmentId());
        List<Department> departmentList = weiXinCompanyService.getDepartmentList(departmentId);
        if (CollectionUtils.isEmpty(departmentList)) {
            return;
        }
        UpdateDepartmentForm form = UpdateDepartmentForm.builder()
                .id(departmentId)
                .parentId(new DepartmentId(Long.parseLong(weixinInvalidDepartmentIdStr)))
                .build();
        weiXinCompanyService.updateDepartment(form);
    }

    public void createDepartment(WxUserInfo wxUserInfo, String departmentName) {
        long parentDepartmentId = wxUserInfo.getDominationIdCode() == null ?
                Long.parseLong(weixinRootDepartmentIdStr) : wxUserInfo.getDominationIdCode().getValue();
        DepartmentId departmentId = new DepartmentId(wxUserInfo.getIdCode().getValue());
        List<Department> departmentList = weiXinCompanyService.getDepartmentList(departmentId);
        if (CollectionUtils.isEmpty(departmentList)) {
            CreateDepartmentForm form = CreateDepartmentForm.builder()
                    .id(departmentId)
                    .name(departmentName)
                    .parentId(new DepartmentId(parentDepartmentId))
                    .build();
            weiXinCompanyService.createDepartment(form);
        } else {
            UpdateDepartmentForm form = UpdateDepartmentForm.builder()
                    .id(departmentId)
                    .parentId(new DepartmentId(parentDepartmentId))
                    .build();
            weiXinCompanyService.updateDepartment(form);
        }
    }

    public void createDealerDepartment(WxUserInfo wxUserInfo) {
        DepartmentId departmentId = new DepartmentId(wxMaxId - wxUserInfo.getIdCode().getValue());
        DepartmentId parentDepartmentId = new DepartmentId(wxUserInfo.getIdCode().getValue());
        List<Department> departmentList = weiXinCompanyService.getDepartmentList(departmentId);
        if (CollectionUtils.isEmpty(departmentList)) {
            CreateDepartmentForm form = CreateDepartmentForm.builder()
                    .id(departmentId)
                    .name("经销商社群")
                    .parentId(parentDepartmentId)
                    .build();
            weiXinCompanyService.createDepartment(form);
        }
    }

    public void updateDepartment(WxUserInfo afterWxUserInfo) {
        long parentDepartmentId = afterWxUserInfo.getDominationIdCode() == null ?
                Long.parseLong(weixinRootDepartmentIdStr) : afterWxUserInfo.getDominationIdCode().getValue();
        UpdateDepartmentForm form = UpdateDepartmentForm.builder()
                .id(new DepartmentId(afterWxUserInfo.getDepartmentId()))
                .parentId(new DepartmentId(parentDepartmentId))
                .build();
        weiXinCompanyService.updateDepartment(form);
        wxUserInfoRepository.insertOrUpdate(afterWxUserInfo);
    }

    /**
     * 删除成员的部门信息
     *
     * @param wxUserInfo
     */
    public void deleteUserDepartment(WxUserInfo wxUserInfo) {
        // 删除成员的部门信息，删除wx_user_info
        String idCodeStr = wxUserInfo.getIdCode().toString();
        WechatUser wechatUser = getWechatUser(idCodeStr);
        List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
        List<Long> departmentIdValList = departmentIdList.stream()
                .map(DepartmentId::getValue)
                .collect(Collectors.toList());
        departmentIdValList.add(Long.parseLong(weixinInvalidDepartmentIdStr));
        departmentIdValList.remove(wxUserInfo.getDepartmentId());
        departmentIdList = departmentIdValList.stream()
                .map(DepartmentId::new)
                .collect(Collectors.toList());
        UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                .userId(idCodeStr)
                .department(departmentIdList)
                .build();
        weiXinCompanyService.updateUser(form);
        wxUserInfoRepository.deleteByIdCode(wxUserInfo.getIdCode());
    }

    public void updateUserDepartment(WxUserInfo beforeWxUserInfo, WxUserInfo afterWxUserInfo) {
        String idCodeStr = afterWxUserInfo.getIdCode().toString();
        WechatUser wechatUser = getWechatUser(idCodeStr);
        WxUserInfo existWxUserInfo = wxUserInfoRepository.selectByIdCode(afterWxUserInfo.getIdCode());
        if (existWxUserInfo == null) {
            throw ApplicationException.error(WORK_WEIXIN_DEALER_INFO_NOT_EXIST, idCodeStr);
        }
        List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
        List<Long> departmentIdValList = departmentIdList.stream()
                .map(DepartmentId::getValue)
                .collect(Collectors.toList());
        if (!departmentIdValList.contains(afterWxUserInfo.getDepartmentId())) {
            departmentIdValList.add(afterWxUserInfo.getDepartmentId());
        }
        departmentIdValList.remove(beforeWxUserInfo.getDepartmentId());
        List<DepartmentId> newDepartmentIdList = departmentIdValList.stream()
                .map(DepartmentId::new)
                .collect(Collectors.toList());
        UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                .userId(idCodeStr)
                .department(newDepartmentIdList)
                .build();
        weiXinCompanyService.updateUser(form);
        wxUserInfoRepository.insertOrUpdate(afterWxUserInfo);
    }

    public void createUserDepartment(WxUserInfo wxUserInfo, CrmDealerInfo crmDealerInfo) {
        String idCodeStr = wxUserInfo.getIdCode().toString();
        WechatUser wechatUser = weiXinCompanyService.getUser(idCodeStr);
        if (wechatUser != null) {
            List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
            List<Long> departmentIdValList = departmentIdList.stream()
                    .map(DepartmentId::getValue)
                    .collect(Collectors.toList());
            if (!departmentIdValList.contains(wxUserInfo.getDepartmentId())) {
                departmentIdValList.add(wxUserInfo.getDepartmentId());
            }
            departmentIdValList.remove(Long.parseLong(weixinInvalidDepartmentIdStr));
            departmentIdList = departmentIdValList.stream()
                    .map(DepartmentId::new)
                    .collect(Collectors.toList());
            UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                    .userId(idCodeStr)
                    .department(departmentIdList)
                    .build();
            weiXinCompanyService.updateUser(form);
        } else {
            CreateWechatUserForm form = new CreateWechatUserForm();
            form.setUserId(idCodeStr);
            form.setName(StringUtils.isEmpty(crmDealerInfo.getUserName()) ? idCodeStr : crmDealerInfo.getUserName());
            form.setMobile(crmDealerInfo.getMobile());
            form.setDepartment(List.of(new DepartmentId(wxUserInfo.getDepartmentId())));
            form.setToInvite(weixinUserToInvite);
            weiXinCompanyService.createUser(form);
            wxUserInfo.setWxActivateStatus(WxActivateStatus.NOT_ACTIVE);
        }
        wxUserInfoRepository.insertOrUpdate(wxUserInfo);
    }

    public void addIntoCurrentDepartment(WxUserInfo afterWxUserInfo) {
        UserIdCode dominationIdCode = afterWxUserInfo.getDominationIdCode();
        if (dominationIdCode != null) {
            Long departmentId = afterWxUserInfo.getDepartmentId();
            WechatUser wechatUser = getWechatUser(dominationIdCode.toString());
            List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
            List<Long> departmentIdValList = departmentIdList.stream()
                    .map(DepartmentId::getValue)
                    .collect(Collectors.toList());
            if (!departmentIdValList.contains(departmentId)) {
                departmentIdValList.add(departmentId);
                departmentIdList = departmentIdValList.stream()
                        .map(DepartmentId::new)
                        .collect(Collectors.toList());
                UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                        .userId(dominationIdCode.toString())
                        .department(departmentIdList)
                        .build();
                weiXinCompanyService.updateUser(form);
            }
        }
    }

    public void  moveOutCurrentDepartment(WxUserInfo afterWxUserInfo) {
        UserIdCode dominationIdCode = afterWxUserInfo.getDominationIdCode();
        if (dominationIdCode != null) {
            Long departmentId = afterWxUserInfo.getDepartmentId();
            WechatUser wechatUser = getWechatUser(dominationIdCode.toString());
            List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
            List<Long> departmentIdValList = departmentIdList.stream()
                    .map(DepartmentId::getValue)
                    .collect(Collectors.toList());
            if (departmentIdValList.remove(departmentId)) {
                departmentIdList = departmentIdValList.stream()
                        .map(DepartmentId::new)
                        .collect(Collectors.toList());
                UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                        .userId(dominationIdCode.toString())
                        .department(departmentIdList)
                        .build();
                weiXinCompanyService.updateUser(form);
            }
        }
    }

    public void addIntoDealerDepartment(WxUserInfo afterWxUserInfo) {
        Long departmentId = wxMaxId - afterWxUserInfo.getIdCode().getValue();
        WechatUser wechatUser = getWechatUser(afterWxUserInfo.getIdCode().toString());
        List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
        List<Long> departmentIdValList = departmentIdList.stream()
                .map(DepartmentId::getValue)
                .collect(Collectors.toList());
        if (!departmentIdValList.contains(departmentId)) {
            departmentIdValList.add(departmentId);
            departmentIdList = departmentIdValList.stream()
                    .map(DepartmentId::new)
                    .collect(Collectors.toList());
            UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                    .userId(afterWxUserInfo.getIdCode().toString())
                    .department(departmentIdList)
                    .build();
            weiXinCompanyService.updateUser(form);
        }
    }

    public void createDepartmentLimitAccessToOutsideDepartmentsTag(WxUserInfo afterWxUserInfo) {
        long departmentId = afterWxUserInfo.getIdCode().getValue();
        long dealerDepartmentId = wxMaxId - departmentId;
        List<DepartmentId> departmentIdList = new ArrayList<>();
        departmentIdList.add(new DepartmentId(departmentId));
        departmentIdList.add(new DepartmentId(dealerDepartmentId));

        Long limitAccessToOutsideDepartmentsTagId = weixinTagMap.get(WechatWorkTag.LIMIT_ACCESS_TO_OUTSIDE_DEPARTMENTS.getCode());

        weiXinCompanyService.addTagUsers(
                new TagId(limitAccessToOutsideDepartmentsTagId),
                null,
                departmentIdList);
    }

    public void moveOutDealerDepartment(WxUserInfo afterWxUserInfo) {
        Long departmentId = wxMaxId - afterWxUserInfo.getIdCode().getValue();
        WechatUser wechatUser = getWechatUser(afterWxUserInfo.getIdCode().toString());
        List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
        List<Long> departmentIdValList = departmentIdList.stream()
                .map(DepartmentId::getValue)
                .collect(Collectors.toList());
        if (departmentIdValList.contains(departmentId)) {
            departmentIdValList.remove(departmentId);
            departmentIdList = departmentIdValList.stream()
                    .map(DepartmentId::new)
                    .collect(Collectors.toList());
            UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                    .userId(afterWxUserInfo.getIdCode().toString())
                    .department(departmentIdList)
                    .build();
            weiXinCompanyService.updateUser(form);
        }
    }

    public void historyAddIntoCurrentDepartment(WxUserInfo beforeWxUserInfo, WxUserInfo afterWxUserInfo) {
        String beforeWxUserInfoIdCode = beforeWxUserInfo.getIdCode().toString();
        long afterWxUserInfoIdCode = afterWxUserInfo.getIdCode().getValue();
        WechatUser wechatUser = getWechatUser(beforeWxUserInfoIdCode);
        List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
        List<Long> departmentIdValList = departmentIdList.stream()
                .map(DepartmentId::getValue)
                .collect(Collectors.toList());
        if (!departmentIdValList.contains(afterWxUserInfoIdCode)) {
            departmentIdValList.add(afterWxUserInfoIdCode);
            departmentIdList = departmentIdValList.stream()
                    .map(DepartmentId::new)
                    .collect(Collectors.toList());
            UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                    .userId(beforeWxUserInfoIdCode)
                    .department(departmentIdList)
                    .build();
            weiXinCompanyService.updateUser(form);
            wxUserInfoRepository.updateHistoryDominationIdCode(afterWxUserInfo);
        }
    }

    private WechatUser getWechatUser(String beforeWxUserInfoIdCode) {
        WechatUser wechatUser = weiXinCompanyService.getUser(beforeWxUserInfoIdCode);
        if (wechatUser == null) {
            throw ApplicationException.error(WORK_WEIXIN_DEALER_INFO_NOT_EXIST, beforeWxUserInfoIdCode);
        }
        return wechatUser;
    }

    public void historyMoveOutCurrentDepartment(WxUserInfo beforeWxUserInfo, WxUserInfo afterWxUserInfo) {
        String beforeWxUserInfoIdCode = beforeWxUserInfo.getIdCode().toString();
        Long departmentId = afterWxUserInfo.getIdCode().getValue();
        WechatUser wechatUser = getWechatUser(beforeWxUserInfoIdCode);
        List<DepartmentId> departmentIdList = wechatUser.getUserInfo().getDepartmentIds();
        List<Long> departmentIdValList = departmentIdList.stream()
                .map(DepartmentId::getValue)
                .collect(Collectors.toList());
        if (departmentIdValList.contains(departmentId)) {
            departmentIdValList.remove(departmentId);
            departmentIdList = departmentIdValList.stream()
                    .map(DepartmentId::new)
                    .collect(Collectors.toList());
            UpdateWechatUserForm form = UpdateWechatUserForm.builder()
                    .userId(beforeWxUserInfoIdCode)
                    .department(departmentIdList)
                    .build();
            weiXinCompanyService.updateUser(form);
            wxUserInfoRepository.updateHistoryDominationIdCode(afterWxUserInfo);
        }
    }
}
